class Task:
    def __init__(self, id, name, duration, predecessors=None):
        self.id = id
        self.name = name
        self.duration = duration
        self.predecessors = predecessors if predecessors else []
        self.successors = []
        self.es = 0
        self.ef = 0
        self.ls = 0
        self.lf = 0
        self.tf = 0

def calculate_cpm(tasks):
    # Forward pass to calculate ES and EF
    for task in tasks:
        if not task.predecessors:
            task.es = 0
        else:
            max_ef = max(pred.ef for pred in task.predecessors)
            task.es = max_ef
        task.ef = task.es + task.duration
    
    # Backward pass to calculate LF and LS
    tasks[-1].lf = tasks[-1].ef
    tasks[-1].ls = tasks[-1].lf - tasks[-1].duration
    tasks[-1].tf = tasks[-1].ls - tasks[-1].es
    
    for task in reversed(tasks[:-1]):
        if not task.successors:
            task.lf = tasks[-1].lf
        else:
            min_ls = min(succ.ls for succ in task.successors)
            task.lf = min_ls
        task.ls = task.lf - task.duration
        task.tf = task.ls - task.es
    
    # Identify critical path
    critical_path = []
    current_task = tasks[0]  # Start with the first task
    critical_path.append(current_task)
    
    while current_task.successors:
        # Find the successor with TF=0 (critical path)
        next_task = None
        for succ in current_task.successors:
            if succ.tf == 0:
                next_task = succ
                break
        
        if next_task is None:
            break  # No more critical tasks
        
        critical_path.append(next_task)
        current_task = next_task
    
    return critical_path

def main():
    # Create tasks based on the report
    task1 = Task(1, "需求分析", 5.0)
    task2 = Task(2, "系统设计", 6.0, [task1])
    task3 = Task(3, "数据采集模块开发", 8.0, [task2])
    task4 = Task(4, "教务管理模块开发", 9.0, [task2])
    task5 = Task(5, "智能推荐模块开发", 6.0, [task2])
    task6 = Task(6, "系统集成测试", 4.0, [task3, task4, task5])
    task7 = Task(7, "部署与验收", 3.5, [task6])
    
    # Set up successor relationships
    task1.successors = [task2]
    task2.successors = [task3, task4, task5]
    task3.successors = [task6]
    task4.successors = [task6]
    task5.successors = [task6]
    task6.successors = [task7]
    
    tasks = [task1, task2, task3, task4, task5, task6, task7]
    
    # Calculate CPM
    critical_path = calculate_cpm(tasks)
    
    # Print results
    print("CPM Analysis Results:")
    print("{:<5} {:<25} {:<8} {:<8} {:<8} {:<8} {:<8}".format(
        "ID", "Task Name", "ES", "EF", "LS", "LF", "TF"))
    for task in tasks:
        print("{:<5} {:<25} {:<8.1f} {:<8.1f} {:<8.1f} {:<8.1f} {:<8.1f}".format(
            task.id, task.name, task.es, task.ef, task.ls, task.lf, task.tf))
    
    print("\nTotal Project Duration: {:.1f} days".format(tasks[-1].ef))
    
    print("\nCritical Path:")
    print(" -> ".join([f"{task.name} ({task.id})" for task in critical_path]))
    
    print("\nRecommendations:")
    print("- Critical path activities have no float time and need close monitoring.")
    print("- Tasks 3 and 5 (data collection and recommendation modules) have float time and can be scheduled flexibly.")
    print("- Prioritize resources for Task 4 to prevent delays in the overall schedule.")

if __name__ == "__main__":
    main()